跳到主要内容

1.6-正则

Create by fall on ---- Recently revised in 26 Sep 2023

## 正则表达式

就像 Math 方法作用于 number 类型的数据一样,正则表达式作用于 string 类型的数据

正则表达式的声明

var box1 = new RegExp('hello','ig');
var box2 = RegExp('hello','ig')
var box3 = /hello/gi
// i 修饰符,表示不区分大小写
// g 修饰符,表示可以选取多个

实例方法

RegExp 对象本身仅有两个实例方法用于对字符串进行判断

  • RegExp.prototype.test():返回该正则是否存在于 string 中(true & false

  • RegExp.prototype.exec():在 string 中返回匹配后的内容

判断正则是否使用了某个关键字

  • RegExp.prototype.dotAll 检测该正则是否处在 dotAll 模式,即有无 s 标记
  • RegExp.prototype.global 检测是否设置 g 标记
  • RegExp.prototype.ignoreCase 是否设置了 i 标记
  • RegExp.prototype.multiline 是否采用了多行模式匹配 m 标记
  • RegExp.prototype.sticky 是否采用了 u 标记
  • RegExp.prototype.unicode 是否采用了 y 标记
  • RegExp.prototype.flags 返回当前正则所用到的所有修饰符
  • RegExp.prototype.source 返回当前正则的匹配内容
const reg1 = /95527/
reg1.test('95df7a6q895527df')
// true
/95527/.exec('95df7a6q895527df')
// ["95527"]
const pattern = /\d55\d/g;
const string = '955553df7a6q8955274554f';
let matches;
while (matches = pattern.exec(string)) {
console.log(matches);
}

const reg2 = /514/gi
reg2.dotAll // false
reg2.global // true
reg2.ignoreCase // true
reg2.multiline // false
reg2.flags // "gi"
reg2.source // "514"
// 是否设置了 `u` 修饰符:
/🤣/u.unicode // true
// 是否设置了 `y` 修饰符
/abc/y.sticky // true

字符串方法中使用

部分 string 类型数据上拥有的方法可以传入正则表达式作为参数

  • String.prototype.match()
    • 功能:在字符串中匹配是否有符合的正则表达式
    • 返回值:返回由字符串组成的数组
  • String.prototype.replace()
    • 功能:用新的字符串(newStr)替换掉旧字符串(oldStr)
    • 返回值:替换成功的新字符串
  • String.prototype.split()
    • 功能:用分隔符将字符串分割
    • 返回值:用字符串分割后的数组
  • String.prototype.search()
    • 功能:找到含有子串或正则的下标
var str = 'hello, my old friend, now it\'s end'
var box1 = /end/;
str.match(box1)
// 返回匹配的字符串,字符串的起始索引,输入内容
// ['end', index: 17, input: "hello, my old friend, now it's end", groups: undefined]

var box2 = /bl/g;
alert(str.replace(box2,'--'));
alert(str.replace('cia','--'));

var box3 = /bl/g;// 本身可以找到全局,可以不用添加 g
alert(str.split(box3));
alert(str.split('dai'));

var box4 = /bl/g;
alert(str.search('are'));
alert(str.search(box4));

元字符

元字符是正则表达式中有特殊含义的字符

常用的元字符

## 单个数字和字符的元字符
- . 匹配任意字符
- [] 匹配指定范围的内容
- `[0-9]` 匹配 0-9 数字
- `[a-zA-Z0-9_]` 数字字母下划线
- `[^0-9]` 非 0-9
- `[^adx]` 非 a、d、x
- \w 等价于 `[A-Za-z0-9_]` 数字字母下划线
- \W 匹配非数字字母下划线
- \d 匹配单个数字
- \D 匹配单个非数字

## 重复字符(限定字符) (x 可以替换为任意单个字符)
- `x?` 匹配 0 个或者 1 个 x 存在或者不存在 x,除此之外(匹配的不是 x)返回 false
- `x+` 至少匹配一个字符 数字可以占多个位置 除此之外返回 false
- `x*` 匹配任意个 x 字符
- `x{m,n}` 匹配至少 m 个,最多 n 个字符
- `(xyz)` 小括号括起来的部分当作单个字符处理
- `x+?` 限定字符是惰性的,并且尽可能匹配更少的该字符

## 锚点字符
- ^ 首匹配
- $ 尾匹配
> 注:同时使用时,意义为从头到尾都需要匹配,否则返回 false

## 多正则匹配
- | 用|隔开想要匹配的多个 出现以上任意一个字符为 true

一般来讲,把字母大写,表示小写字母的补集

不常用的元字符

## 空白字符
- \0 匹配 null 字符
- \f 匹配进纸符
- \n 匹配换行符
- \r 匹配回车符
- \t 匹配制表符
- \s 匹配空白字符,空格,制表符,换行符
- \S 匹配除空白字符,空格,制表符,换行符
- `\p` \p{L}/u 匹配任意语言的字符(除空格数字,emoji 之外)

## 锚点字符(定位字符)
- \A 只匹配字符串的开始处
- \b 只匹配单词边界,词在 [] 内无效 boundaries(界限,边界
- \B 只匹配非单词边界
- \G 只匹配当前搜索的开始位置
- \Z 匹配字符串借书处,或者行尾
- \z 只匹配字符串结尾处

## 前后匹配
- `(?:x)` 匹配 x 但不记录匹配的结果
- `x(?=y)` 当 x 后接 y 时,匹配 x
- `x(?!y)` 当 x 后不是 x 时,匹配 x
// 测试元字符 u,匹配 unicode 
const result1 = /5\p{L}/u.test('45d6') // true
const result2 =/5\p{L}/u.test('45の6')

const string = 'the cat sat on the mat';
const regex = /the.+?on/;
const match = string.match(regex);
console.log(match); // returns ['the cat sat on']

'1345556555513464721321'.match(/1.+?6/) // ["1345556"] 在 1-6之间的数字,匹配越少越好
'1345556555513464721321'.match(/1.+6/) // ["134555655551346"] 在 1-6之间的数字,匹配越多越好

// \b 匹配任何开头是 bet 的单词,忽略大小写
const pattern = /\bbet/gi;
const text = "Betty's better bet was to buy the blue blouse. Albet?";
console.log(text.match(pattern)); // ['Bet', 'bet', 'bet']
// 匹配以 er 结束的单词
const pattern2 = /er\b/g
console.log(text.match(pattern2)); // ['er']

修饰符

修饰符也被称为标记,放在正则表达式后面

  • i 表示不区分大小写
  • g 表示可以同时选取多个
  • m 表示可以换行匹配,每一行的内容独立
  • u 处理大于 \uFFFFUnicode 字符
  • y 同样是全局匹配,只不过匹配内容必须和匹配内容相连
  • s 单行匹配

u 修饰符:含义为 Unicode 模式,用来正确处理大于 \uFFFFUnicode 字符。也就是说,如果待匹配的字符串中可能包含有大于 \uFFFF 的字符,就必须加上 u 修饰符,才能正确处理。

// 加上 u 修饰符才能让 . 字符正确识别大于 \uFFFF 的字符
/^.$/.test('🤣') // false
/^.$/u.test('🤣') // true

// 大括号 Unicode 字符表示法必须加上 u 修饰符
const reg1 = /\u{61}/.test('a') // false
/\u{61}/u.test('a') // true

// 有 u 修饰符,量词才能正确匹配大于 \uFFFF 的字符
/🤣{2}/.test('🤣🤣') // false
/🤣{2}/u.test('🤣🤣') // true

/[^\p{L}\p{N}]+/u.test('dsadf1zxc😁v4341')

// 跨行匹配
const paragraph = `hello
For example, hello at the beginning of a line in a multi-line input string.
hello`
const reg1 = /^hello/gm // [ "hello", "hello" ]

修饰符 y

g 修饰符类似也是全局匹配;不同的是 g 是剩余字符中匹配即可,而 y 则是必须在剩余的第一个字符开始匹配才行,所以 y 修饰符也叫黏连修饰符:

let s = 'aaa_aa_a'
let r1 = /a+/g
let r2 = /a+/y

r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]

r1.exec(s) // ["aa"]
r2.exec(s) // null
// 示例 2
const str1 = 'table foofootballfoo';
const regex1 = new RegExp('foo', 'y');

regex1.lastIndex = 6;
console.log(regex1.sticky);
// Expected output: true
console.log(regex1.test(str1));
// Expected output: true
console.log(regex1.test(str1));
// Expected output: true
console.log(regex1.test(str1));
// Expected output: false

s 修饰符

ES2018 引入,表示按照单行内容匹配

/fall.again/.test('fall\nagain') // false
/fall.again/s.test('fall\nagain') // true

正则用例

let str = 'dfa46546321v/t77/n'
str.match(/\d/g) // 取出所有数字
str.match(/\D/g) // 取出所有非数字
// 匹配 0-8 的数字,数字个数为 1,9 个
str.match(/[0-8]{1,9}/g)

var str = 'ss1baffsdi';
var box = /ss.[a-c]a/;
// 匹配 ss 任意字符 a-c之间的字符,a
box.test(str)

var str = 'goloogu';
var box = /go/w?ogle/;
alert(box.test(str));
// 锚点字符
var str = 'geessagoogle';
var box3 = /^gle/;
alert(box3.test(str));

var str = 'golol';
var box4 = /golol|depp|srect/;// str中出现以上任意一个字符为true
alert(box4.test(str));

// /^[0-9]+\.?[0-9]$|^[0-9]$/ 该正则限定必须为浮点数

动态正则

使用 new 进行创建正则的时候,可以传入字符串,可以根据用户输入的内容进行筛选

function findText(regText,text){
const regex = new RegExp(`${regText}`,'gi')
return regex.test(text)
}

转义字符

使用正则时需要注意转义字符,即如果想在字符串中表示 \ 需要定义为 let str = '\\'

reg = /Scen\\(.*)\.ve/
reg.test('Scen\\把对方.ve') // true

具名匹配

具名匹配,可以将捕获的字符串进行命名,通过命名进行快速查找

没有使用具名匹配

let day = /(\d{4})-(\d{2})-(\d{2})/
let result = day.exec('2021-08-12')
// result[0] === '2021-08-12'
// result[1] === '2021'
// result[2] === '08'
// result[3] === '12'
'2022-02-14'.replace(day,'$1?$2?$3') // '2022?02?14'

使用具名匹配

let day = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
let result = day.exec('2021-08-12')
// result.groups { year: "2021", month: "08", day: "12" }'

配合结构赋值

let {groups: {year, month, day}} = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/.exec('2021-08-12')
console.log(year, month, day) // 2021 08 12

后行断言 (?<=y)xx 只有在 y 后面才能匹配:

/(?<=\$)\d+/.exec('I have $100.')  // ['100']
// 否定断言: (?<!y)x,x 只有不在 y 后面才能匹配:

/(?<!\$)\d+/.exec('I have $100.') // ['00']

前后匹配

// 匹配 is 前面的单词,匹配时包括 is,但是返回时不返回 is
const string = 'The sky is blue'
const regex = /\w+(?=\sis)/g
const matches = string.match(regex);
console.log(matches); // returns ['sky']

const string = 'The cat sat on the mat';
const regex = /(?<=the\s)\w+/gi;
const matches = string.match(regex);
console.log(matches); // returns ['cat', 'mat']
const regex2 = /(?=the\s)\w+/gi;
const matches2 = string.match(regex);
console.log(matches); // returns ['The', 'the']

示例

数字分隔

num.toString().replace(/(\d)(?=(?:\d{3})+$)/g,'$1,')

颜色

let cPattern = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/;

日期格式转换

const date = '02/18/2023';
const regex = /(\d{2})\/(\d{2})\/(\d{4})/;
const newDate = date.replace(regex, '$3-$1-$2');
console.log(newDate); // returns '2023-02-18'

身份证

// 第二代身份证
let isIdentifyCardNo= /^[1-9]\d{5}(18|19|20)\d{2}(1[0-2]|0[1-9])(([1-2][0-9])|(0[1-9])|30|31)\d{3}[0-9Xx]$/

护照

let isTrue=/^(P\d{7}|G\d{7,8}|TH\d{7,8}|S\d{7,8}|A\d{7,8}|L\d{7,8}|\d{9}|D\d+|1[4,5]\d{7})$/;

电话号码

移动号段:134 135 136 137 138 139 147 148 150 151 152 157 158 159 172 178 182 183 184 187 188 198

联通号段:130 131 132 145 146 155 156 166 171 175 176 185 186

电信号段:133 149 153 173 174 177 180 181 189 199

虚拟运营商:170

let isChinaTel = /(13[0-9]\d{7}|14[5-9]|15[0-3]|15[5-9]|166|17[0-8]|18[0-9]|19[8-9])\d{8}$/

固定电话

let isTrue=(/(\d{3,4}\)|\d{3,4}-|\s)?\d{8}/;

邮箱

let isEmail = /^[A-Za-z0-9_\-\.\u4e22-\u9fa5]+\@([A-Za-z0-9_\.\-])+\.([a-zA-Z]{2,8})$/

function validateEmail(email) {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailPattern.test(email);
}
console.log(validateEmail('user@example.com')); // true
console.log(validateEmail('invalid_email')); // false

用户名

// 4-16 位(数字,字母,下划线,减号)
let isUserName = /^[a-zA-Z0-9][a-zA-Z0-9_\-]{3-15}$/

微信号:6-20位,字母开头,支持数字字母,减号下划线

let isWechatName = /^[a-zA-Z]([-_a-zA-Z0-9]{5,19})$/

QQ号码:5-11位

let isQQNum = /^[1-9][0-9]{4,10}$/

密码

密码正则

let isPassword = /^[a-zA-Z0-9]\w{5,17}$/
// 6-18 位密码,只能包含数字字母下划线,只限制密码长度

强密码正则

let isTrue = /^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/;
// 最少 6 位,必须包含1个数字,1个大写字母,一个小写字母,下划线以及特殊符号

特殊字符串

let hasSpecialStr = /["'<>%)(&+?!@#$~*]/

域名和 IP

// 匹配IP
// let isTrue=/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
var urlP= /^((https?|ftp|file):\/\/)?([da-z.-]+).([a-z.]{2,6})([/w .-]*)*\/?$/

匹配 IP 地址

let isIP=/(\d{1,3}\.){3}\d{1,3}/
// 不能约束 255 - 300 的内容
let isIP = /^(([0-9]|[1-2](\d{1,2})|[3-9]\d)\.){3}([0-9]|[1-2](\d{1,2})|[3-9]\d)$/
// 严格约束 0-255
var ipP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;

匹配网址

const text = 'Check out this site: https://www.example.com and also this one: https://www.another-example.com';
const urls = text.match(/https?:\/\/\S+/g);
urls // ['https://www.example.com', 'https://www.another-example.com']

车牌号

let isTrue = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/

中文正则

// 限制内容必须为中文,同时可以用于检验是否是真实姓名
var str= '人民万岁';
var box5 = /^[\u4e00-\u9fa5]+$/;
str.test()

邮政编码

let isTrue = /[1-9](\d+){5}/
isTrue.test('100036')

经纬度

// 经度正则
let isTrue=/^(\-|\+)?(((\d|[1-9]\d|1[0-7]\d|0{1,3})\.\d{0,6})|(\d|[1-9]\d|1[0-7]\d|0{1,3})|180\.0{0,6}|180)$/;
// 纬度正则
let isTrue=/^(\-|\+)?([0-8]?\d{1}\.\d{0,6}|90\.0{0,6}|[0-8]?\d{1}|90)$/

移除重复文本

const string = 'the the cat sat on the mat';
// \1 表示捕获到的单词,然后使用捕获到的单词去替换,有效的剔除重复的单词
const regex = /\b(\w+)\b\s+\1/g;
const newString = string.replace(regex, '$1');
console.log(newString); // Output: 'the cat sat on the mat.'

路径中的文件名

"/adufadsf/sdfa.png".match(/\w{0,40}\.png$/)

参考文章

作者链接
OBKoro1https://juejin.cn/post/6844903602591383565
前端表单验证常用的15个JS正则表达式http://caibaojian.com/form-regexp.html
Adebayo Adamshttps://www.honeybadger.io/blog/javascript-regular-expressions/